package se.webbzon.oschi01.worldobject;

import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldarea.WorldLiveness;
import se.webbzon.oschi01.worldcamera.WorldCameraPane;

public abstract class WorldObject {
	
	// The methods which can be registered for an instance of WorldObject
	public static final int onCreate 	= (1<<0);
	public static final int onDestroy 	= (1<<1);
	public static final int onStepBegin	= (1<<2);
	public static final int onStep 		= (1<<3);
	public static final int onStepEnd 	= (1<<4);
	public static final int onPreDraw 	= (1<<5);
	public static final int onDraw 		= (1<<6);
	public static final int onPostDraw 	= (1<<7);
	public static final int onAreaEnter	= (1<<8);
	public static final int onAreaLeave	= (1<<9);
	
	// The registered methods for this instance
	private final int registeredMethods;
	
	// The depth (order of drawing) of the onPreDraw and onPostDraw events.
	private final int depth2D;
	
	// The world in which the instance exists
	private WorldArea world;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new abstract WorldObject with a given set of
	 * registered methods which will be launched under the given
	 * circumstances. The 2D-depth of the instance will be equal
	 * to zero. **/
	public WorldObject(int registeredMethods) {
		this(registeredMethods,0);
	}
	
	/** Creates a new abstract WorldObject with a given set of
	 * registered methods which will be launched under the given
	 * circumstances. The 2D-depth of the instance is given by
	 * the input depth2D. **/
	public WorldObject(int registeredMethods, int depth2D) {
		this.depth2D = depth2D;
		this.registeredMethods = registeredMethods;
		world = null;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns a compilation of the registered methods of this instance.
	 * This methods can be used to check whatever an instance has an
	 * implementation of a certain method by ANDing the returned
	 * value with WorldObject.onCreate, WorldObject.onStep, (...). **/
	public final int getRegisteredMethods() {
		return registeredMethods;
	}
	
	/** Returns the depth (order of drawing) of the onPreDraw and
	 * onPostDraw events. **/
	public final int getDepth2D() {
		return depth2D;
	}
	
	/** This methods will be launched one when the instance
	 *  is added to the WorldArea. **/
	public void onCreate(WorldArea world) {};
	
	/** This method will be launched in the beginning of every
	 * global step in the WorldArea. **/
	public void onStepBegin(WorldArea world) {};
	
	/** This method will be launched once during each global 
	 * step in the WorldArea. */
	public void onStep(WorldArea world) {};
	
	/** This method will be launched in the end of every 
	 * global step in the WorldArea. **/
	public void onStepEnd(WorldArea world) {};
	
	/** This method will be launched before 3D rendering
	 * starts. This method gives an instance a change
	 * to draw behind the 3D scene. Notice that this
	 * method is not synchronized with the global stepping. **/
	public void onPreDraw(WorldArea world, WorldCameraPane background) {};
	
	/** This method will be launched when rendering the 3D environment. 
	 * This method givens an instance a change to change its visual content
	 * inside the 3D scene. Notice that this method is not synchronized with 
	 * the global stepping. **/
	public void onDraw(WorldArea world) {};
	
	/** This method will be launched after 3D rendering
	 * starts. This method gives an instance a change
	 * to draw in front of the 3D scene. Notice that this
	 * method is not synchronized with the global stepping.**/
	public void onPostDraw(WorldArea world, WorldCameraPane hud) {};
	
	/** This method will be launched when the instance is removed from
	 * the WorldArea. **/
	public void onDestroy(WorldArea world) {};
	
	/** This method will be launched when the WorldArea starts due to
	 * a WorldArea switch in the WorldAreaEngine. **/
	public void onAreaEnter(WorldArea world) {};
	
	/** This method will be launched when the WorldArea stops due to
	 * a WorldArea switch in the WorldAreaEngine. **/
	public void onAreaLeave(WorldArea world) {};
	
	/** Returns true if the instance exists inside an WorldArea. **/
	public final boolean exists() {
		return world != null;
	}
	
	/** Returns the world in which the instance has been created. If the
	 * instance has not yet been created then null is returned. **/
	public final WorldArea getWorld() {
		return world;
	}
	
	/** Creates the instance inside a WorldArea. This method should only be
	 * called by the WorldArea which the instance is created in. **/
	public final boolean create(WorldArea world) {
		if (this.world == null) {
			this.world = world;
			return true;
		} else 
			return false;
	}
	
	/** Destroys the instance inside a WorldArea. This method should only be
	 * called by the WorldArea which the instance is created in. **/
	public final boolean destroy(WorldArea world) {
		if (this.world == world) {
			this.world = null;
			return true;
		} else 
			return false;
	}
	
	/** Returns true if this instance is created in a WorldArea which is
	 * currently live according to the class WorldLiveness. **/
	public final boolean isLive() {
		if (this.world == null)
			return false;
		else
			return WorldLiveness.instance().isLive(world);
	}

}
